#include "stm32f10x.h"    
#include "freertos.h"
#include "task.h"
#include "queue.h"
#include "Delay.h"

#include <string.h>

#include "USART_Config.h"
#include "ESP01s_Control.h"
#include "HC05_Control.h"
#include "LED_Init.h"
#include "Buzzer_Init.h"
#include "OLED.h"

#define QUEUE_LENGTH 16	 					// 队列长度
#define ITEM_SIZE sizeof(USART_Message_t)	// 队列项大小
QueueHandle_t xQueue;

void USART_Handler(void);
void vTask_USART_Controller(void *arg);
void vTask_ESP01s_Heartbeat(void *arg);

/*
// ========== 发文表述 ==========
//	 1. 查过资料
	 2. 分享思路
	 3. 对不对
// ========== 代码思路 ==========
	 1. 先写框架
	 2. 再写内容
// ========== 1期内容 ==========
// √ 1. ESP-01控制
		【应该没什么大问题，等芯片到达以后测试就可以啦】
		- 连接网络
		- 结构体设置ESP-01状态，实现开启与关闭连接（“+++”透传使用USARTSendBuffer，通过FLAG切换状态，测试效果）
		- 已经确认wifi`连接时，自动联网
// √ 2. 服务器实现与手机通信
		【IP：47.111.20.8，root, ABC12345】
		- 手机端获取正确的通信格式
		- 服务器根据PacketID区分来源（STM32/手机/其他）
		- 修改手机的通信报文
// √ 3. 服务器超时踢出功能
		- 使用FreeRTOS的 xTaskCreate + vTaskDelay；
		- 实现STM32的每分钟心跳包
// √ 4. 设备状态转发
		- 定义LED/蜂鸣器控制结构体
		- 实现LED/蜂鸣器设备状态报文
		- 初始化LED/蜂鸣器GPIO
		- 将硬件操作封装成函数
// √ 5. STM32硬件控制
		【不知道行不行，等芯片到达以后测试】
		- 增加OLED显示状态
		- 优化显示状态的逻辑
// √ 6. 手机客户端接受信息
		- 在服务器添加客户端管理列表
		- 实现手机连接服务器	
// × 7. 修改消息格式，减少发送格式错误，避免粘包与半包
		【未完全修改，修改了发送格式USART_SendString，未修改粘包与半包，发现收发消息逻辑都要改，太懒了，小项目还能凑活用】
		- 中断发送与接收分开处理
		- 将消息改为小火车：结构体+数据两次发送
// × 8. 增加蓝牙，传向ESP-01
		【经过多次努力，USART3引脚还是没能收到任何内容，蓝牙能连上，然而根本不触发我的中断，我放弃了】

// ========== 2期内容 ==========
// √ 1. 增加服务器日志功能
		- 普通日志文件
		- 日志严重程度分类INFO，ERROR，向上兼容
//   2. 增加服务器配置文件功能
//   3. 增加ADC传感器
		- 扫描端口，以结构体保存Buzzer, ADC设备状态
		- 温度云端处理
		- 报警

// ========== 3期内容 ==========
//   1. 将蓝牙、WIFI的账号密码记入STM32 flush中
		- 看门狗复位
		- 自动连接蓝牙
		- （ESP分支-是否连接-是否有flag）自动连接WIFI，发送AT指令，询问联网状态
		
// ========== 4期内容 ==========
//   1. 增加外存flush

// ========== 拓展内容 ==========
//   1. 增加用户通过网页端向STM32发送指令，控制设备
	【设置按钮点击，随便乱输容易被黑掉】
	- 服务器端发送代码
	- 用户端发送代码
	- 用户端设置按钮

*/

int main(void){
	Delay_Init();						// 初始化 Delay函数
	
	USART_Pin_Init(&USART1_Cfg);  		// 初始化 USB_TO_TTL
	USART_Pin_Init(&USART2_Cfg);  		// 初始化 ESP01s
	USART_Pin_Init(&USART3_Cfg);  		// 初始化 HC05
	USART_NVIC_Init(&USART1_Cfg);  		// 初始化 中断源优先级
	USART_NVIC_Init(&USART2_Cfg);  		
	USART_NVIC_Init(&USART3_Cfg);  
	
	LED_Init();
	Buzzer_Init();
	OLED_Init();
	
//	OLED_Clear();
//	OLED_ShowString(1, 1, "(^v^)/ hello!");
//	OLED_ShowString(2, 1, "Connecting to hc-05   >>>");
//	HC_AutoConnect();					// 上电以后自动连接与更新OLED显示状态	
	
	// HC-05到ESP01的状态切换
	OLED_Clear();
	OLED_ShowString(1, 1, "(^v^)/ hello!");
	OLED_ShowString(2, 1, "Connecting to esp-01s >>>");
	ESP_AutoConnect();					// 上电以后自动连接与更新OLED显示状态	
	
	xQueue = xQueueCreate(QUEUE_LENGTH,  ITEM_SIZE);

	xTaskCreate(vTask_USART_Controller, "vTask_LED_Controller", configMINIMAL_STACK_SIZE * 4, NULL, 2, NULL);	
	vTaskStartScheduler();				// 启动调度器，调试到此处按F11
	
	while(1);							// 程序不应执行到这里
}

void vTask_USART_Controller(void *arg) {	
	USART_Message_t msg;
	char msg_rev[MAX_STR_LEN] = {0};
	
    while(1) {		
		if(xQueueReceive(xQueue, &msg, 500) == pdPASS){			// 写portMAX_DELAY会被持续阻塞			
			if(msg.source_id == 1){
				USART_printf(&USART1_Cfg, "USART1 Receive the str: %s \r\n", (msg_rev));	
				memset(msg_rev, sizeof(msg_rev), 0);
			}
			if(msg.source_id == 2){
				// 测试语句，后期删掉1. 3. 4.
				strcpy(msg_rev, (const char*)msg.data);
				ESP_StateTransition(msg_rev); 
				USART_printf(&USART1_Cfg, "USART2 Receive the str: %s \r\n", (msg_rev));	// 注意此处输出到屏幕，而非ESP-01
				memset(msg_rev, sizeof(msg_rev), 0);
								
			}
			if(msg.source_id == 3){
				OLED_ShowString(1, 1, "UR3 REVD MSG");
//				HC_StateTransition((char*)msg.data);
			}
		}
		vTaskDelay(500);
	}
}
